// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:ffigen/src/code_generator/imports.dart';
import 'package:ffigen/src/config_provider/config.dart';
import 'package:ffigen/src/config_provider/config_types.dart';
import 'package:ffigen/src/header_parser.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';

import '../test_utils.dart';

void main() {
  group('large_test', () {
    setUpAll(() {
      logWarnings(Level.SEVERE);
    });
    test('Libclang test', () {
      final config = Config(
        wrapperName: 'LibClang',
        wrapperDocComment: 'Bindings to LibClang.',
        output: Uri.file('unused'),
        compilerOpts: [
          ...defaultCompilerOpts(),
          '-Ithird_party/libclang/include',
        ],
        commentType: CommentType(
          CommentStyle.doxygen,
          CommentLength.brief,
        ),
        entryPoints: [Uri.file('third_party/libclang/include/clang-c/Index.h')],
        shouldIncludeHeaderFunc: (Uri header) => [
          'BuildSystem.h',
          'CXCompilationDatabase.h',
          'CXErrorCode.h',
          'CXString.h',
          'Documentation.h',
          'FataErrorHandler.h',
          'Index.h',
        ].any((filename) => header.pathSegments.last == filename),
        functionDecl: DeclarationFilters.includeAll,
        structDecl: DeclarationFilters.includeAll,
        enumClassDecl: DeclarationFilters.includeAll,
        macroDecl: DeclarationFilters.includeAll,
        typedefs: DeclarationFilters.includeAll,
        typedefTypeMappings: [
          ImportedType(ffiImport, 'Int64', 'int', 'time_t'),
        ],
        preamble: '''
// ignore_for_file: camel_case_types, non_constant_identifier_names
''',
      );
      final library = parse(config);

      matchLibraryWithExpected(
        library,
        'large_test_libclang.dart',
        ['test', 'large_integration_tests', '_expected_libclang_bindings.dart'],
        // Remove comments containing @ to hack around a mismatch in the
        // documentation generated by different clang versions.
        codeNormalizer: (code) =>
            code.replaceAll(RegExp('[^\n]*///[^\n]*@[^\n]*\n'), ''),
      );
    });

    test('CJSON test', () {
      final config = Config(
        wrapperName: 'CJson',
        wrapperDocComment: 'Bindings to Cjson.',
        output: Uri.file('unused'),
        entryPoints: [Uri.file('third_party/cjson_library/cJSON.h')],
        shouldIncludeHeaderFunc: (Uri header) =>
            header.pathSegments.last == 'cJSON.h',
        functionDecl: DeclarationFilters.includeAll,
        structDecl: DeclarationFilters.includeAll,
        macroDecl: DeclarationFilters.includeAll,
        typedefs: DeclarationFilters.includeAll,
        preamble: '''
// ignore_for_file: camel_case_types, non_constant_identifier_names
''',
      );
      final library = parse(config);

      matchLibraryWithExpected(
        library,
        'large_test_cjson.dart',
        ['test', 'large_integration_tests', '_expected_cjson_bindings.dart'],
      );
    });

    test('SQLite test', () {
      // Excluding functions that use 'va_list' because it can either be a
      // Pointer<__va_list_tag> or int depending on the OS.
      final config = Config(
        wrapperName: 'SQLite',
        wrapperDocComment: 'Bindings to SQLite.',
        output: Uri.file('unused'),
        commentType: CommentType(
          CommentStyle.any,
          CommentLength.full,
        ),
        entryPoints: [Uri.file('third_party/sqlite/sqlite3.h')],
        shouldIncludeHeaderFunc: (Uri header) =>
            header.pathSegments.last == 'sqlite3.h',
        functionDecl: DeclarationFilters(
          shouldInclude: (declaration) => !{
            'sqlite3_vmprintf',
            'sqlite3_vsnprintf',
            'sqlite3_str_vappendf',
          }.contains(declaration.originalName),
        ),
        structDecl: DeclarationFilters.includeAll,
        globals: DeclarationFilters.includeAll,
        macroDecl: DeclarationFilters.includeAll,
        typedefs: DeclarationFilters.includeAll,
        preamble: '''
// ignore_for_file: camel_case_types, non_constant_identifier_names
''',
      );
      final library = parse(config);

      matchLibraryWithExpected(
        library,
        'large_test_sqlite.dart',
        ['test', 'large_integration_tests', '_expected_sqlite_bindings.dart'],
      );
    });
  });
}
